#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>

// 节点结构
typedef struct node
{
    int data;
    struct node *next;
} Node;
// 永远指向链表头部的指针
Node *head = NULL;

sem_t producer_t;
sem_t comsumer_t;

void *producer(void *arg)
{
    while (1)
    {
        sem_wait(&producer_t);
        // 创建一个链表的节点
        Node *pnew = (Node *)malloc(sizeof(Node));
        // 节点的初始化
        pnew->data = rand() % 1000;
        // 使用互斥锁保护数据
        pnew->next = head;
        head = pnew;
        printf("======producer: %lu, %d\n", pthread_self(), pnew->data);

        sem_post(&comsumer_t); // 通知消费者消费。
        sleep(rand() % 5);
    }
    return NULL;
}

void *comsumer(void *arg)
{
    while (1)
    {
        // 判断链表是否为空
        sem_wait(&comsumer_t);
        // 链表不为空， 删掉一个节点，删除头结点
        Node *pdel = head;
        head = head->next;
        printf("---------comsumer: %lu, %d\n", pthread_self(), pdel->data);
        free(pdel);
        sem_post(&producer_t); // 通知生产者生产
        sleep(rand() % 5);
    }
}

int main()
{
    // 带有四个信号量的线程同步
    sem_init(&producer_t, 0, 4); // 初始化生产者线程信号量
    sem_init(&comsumer_t, 0, 0); // 初始化消费者线程信号量 不给消费者分配资源
    pthread_t p1, p2, p3, p4, p5;
    // 创建生产者线程
    pthread_create(&p1, NULL, producer, NULL);
    pthread_create(&p2, NULL, producer, NULL);
    pthread_create(&p3, NULL, producer, NULL);
    pthread_create(&p4, NULL, producer, NULL);
    // 创建消费者线程
    pthread_create(&p5, NULL, comsumer, NULL);
    // 阻塞回收子线程
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);
    pthread_join(p3, NULL);
    pthread_join(p4, NULL);
    pthread_join(p5, NULL);
    sem_destroy(&producer_t);
    sem_destroy(&comsumer_t);
}
